<?php

namespace App\Kuafu\Pay\Model;

use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\Base\Model\Traits\KfSplitRelation;
use App\Kuafu\CustomPayment\Model\CustomPaymentModel;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Service\OrderDb;
use App\Kuafu\Pay\Enum\BasePayEnum;
use App\Kuafu\Pay\Enum\PayCodeEnum;
use App\Kuafu\Pay\Exceptions\PayException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class RefundStreamModel extends BaseModel
{
    use HasFactory;
    use KfSplitRelation;

    protected $connection   = 'mysql';
    protected $table        = 'refund_stream';
    protected $primaryKey   = 'refundNo';
    public    $incrementing = false;
    protected $keyType      = 'string';

    protected $fillable = [
        'refundNo',
        'shopId',
        'payNo',
        'orderId',
        'thirdRefundNo',
        'refundChannel',
        'refundChannelChild',
        'refundType',
        'refundPrice',
        'refundStatus',
        'refundSuccessTime',
        'refundFeeRate',
        'refundFee',
        'sysType',
        'callbackUrl',
        'subject',
    ];

    const REFUND_TYPE_NULL  = 0; // 默认
    const REFUND_TYPE_TOTAL = 1; // 全额退
    const REFUND_TYPE_PART  = 2; // 部分退

    const REFUND_STATUS_NULL  = 0; // 默认
    const REFUND_STATUS_ING   = 1; // 退款中
    const REFUND_STATUS_OK    = 2; // 退款成功
    const REFUND_STATUS_ERROR = 3; // 退款失败

    const REFUND_STATUSES = [
        self::REFUND_STATUS_NULL  => '默认',
        self::REFUND_STATUS_ING   => '退款中',
        self::REFUND_STATUS_OK    => '退款成功',
        self::REFUND_STATUS_ERROR => '退款失败',
    ];

    public function getRefundChannelChildTextAttribute()
    {
        return PayStreamModel::PAY_CHANNEL_CHILD_TEXT[$this->refundChannelChild] ?? '';
    }

    /**
     * 创建退款订单
     * @param string $refundNo
     * @param int $shopId
     * @param int $orderId
     * @param string $payNo
     * @param int $refundChannel
     * @param int $refundChannelChild
     * @param int $refundType
     * @param int $refundPrice
     * @return Builder|\Illuminate\Database\Eloquent\Model
     */
    public static function addData(
        string $refundNo,
        int $shopId,
        int $orderId,
        string $payNo,
        int $refundChannel,
        int $refundChannelChild,
        int $refundType,
        int $refundPrice,
        int $sysType = PayStreamModel::SYS_TYPE_RMS_MEAL,
        string $subject = ''
    ) {
        try {

            // 安全保护，强制重写PayChannelChild
            if ($refundChannel == PayStreamModel::PAY_CHANNEL_ALI) {
                $refundChannelChild = PayStreamModel::PAY_CHANNEL_CHILD_ALI;
            } elseif ($refundChannel == PayStreamModel::PAY_CHANNEL_WX) {
                $refundChannelChild = PayStreamModel::PAY_CHANNEL_CHILD_WX;
            }

            return self::query()->create([
                'refundNo'           => $refundNo,
                'shopId'             => $shopId,
                'orderId'            => $orderId,
                'payNo'              => $payNo,
                'refundChannel'      => $refundChannel,
                'refundChannelChild' => $refundChannelChild,
                'refundType'         => $refundType,
                'refundPrice'        => $refundPrice,
                'refundFeeRate'      => PayStreamModel::payChannelRate($refundChannel),
                'refundFee'          => round(PayStreamModel::payChannelRate($refundChannel) * $refundPrice, 0),
                'sysType'            => $sysType,
                'subject'            => $subject,
            ]);
        } catch (\Exception $e) {
            throw new PayException(PayCodeEnum::ERR_REFUND_DB_ADD, '', $e);
        }
    }

    /**
     * 退款成功
     * @param string $refundNo
     * @param int $refundSuccessTime
     * @param string $thirdRefundNo
     * @return bool
     */
    public static function refundSuccess(string $refundNo, int $refundSuccessTime, string $thirdRefundNo): bool
    {
        $query = self::query()->where('refundNo', $refundNo)->first();
        if (!$query) {
            return false;
        }

        $query->refundStatus      = self::REFUND_STATUS_OK;
        $query->refundSuccessTime = $refundSuccessTime;

        if (!$query->thirdRefundNo && $thirdRefundNo) {
            $query->thirdRefundNo = $thirdRefundNo;
        }

        return (bool)$query->save();
    }

    public function getSettlementPriceAttribute()
    {
        return $this->refundPrice - $this->refundFee;
    }

    public function streamCustomPaymentRel()
    {
        return $this->hasOne(CustomPaymentModel::class, 'id', 'refundChannel');
    }

    /**
     * 在配合get()，使用with时，需要提前设置BaseModel::$splitShopId ！！！！！
     * 使用first()是，不要使用with()
     *
     * @return HasOne
     * @throws \Exception
     */
    public function payStreamRel()
    {
        // TODO
        if (isset($this->shopId) && $this->shopId !== null) {
            self::$splitShopId = $this->shopId;
        }

        $tableName = (new PayStreamModel)->getBaseTable();
        $connect = OrderDb::orderDbConnection(self::$splitShopId);

        return $this->hasOneWithTable(PayStreamModel::class, 'payNo', 'payNo', $tableName, $connect);
    }

    /**
     * 退款失败
     * @param string $refundNo
     * @return bool
     */
    public static function refundFail(string $refundNo)
    {
        return (bool)self::query()->where('refundNo', $refundNo)->update(['refundStatus' => self::REFUND_STATUS_ERROR]);
    }

    public function getRefundStatusTextAttribute()
    {
        return static::REFUND_STATUSES[$this->refundStatus] ?? '';
    }

    /**
     * @param $orderIds
     * @param $field
     * @return array
     */
    public static function getRefundStreamByOrderIds($orderIds, $field): array
    {
        return self::query()
                   ->whereIn('orderId', $orderIds)
                   ->select($field)
                   ->get()
                   ->toArray();
    }

    /**
     * @param $orderIds
     * @param $field
     * @return array
     */
    public static function getRefundStreamByPayNos($orderNos, $field): array
    {
        return self::query()
                   ->select($field)
                   ->whereIn('payNo', $orderNos)
                   ->where('refundStatus', RefundStreamModel::REFUND_STATUS_OK)
                   ->groupBy('payNo')
                   ->get()
                   ->toArray();
    }
}
